
import socket
import binascii
import hashlib
import getpass


from time import sleep
from socket import *
from binascii import *
from hashlib import *

import flap
import snac
import vars




from flap import *
from snac import *
from vars import *


sn =""
password =""

def authorize(host, port, sn=None, password=None):
#    print "Logging in as ", sn, " with password", password
    buf = 1024
    addr = (host, port)
#    print addr
    stream = socket(AF_INET, SOCK_STREAM)

    
    if (not stream.connect_ex(addr)):
        print "Authorization Socket Connected"
 
    else:
        print "Connection could not be opened with server"
        return


    if sn == None:
        sn = raw_input("Enter Screen Name:\n")
    vars.buddyName = sn

    #Create an send New Connection Packet
    f = flap()
    f.writeFlap("01")
    f.SNAC.writeNewConnection()
    send(stream, f)

    #Receive New Connection Reply
    r = flap()
    get(stream, r)

    #Create and send SNAC 1706, Signon Request
    f.writeFlap("02")
    f.SNAC.write1706(sn)
    send(stream,f)

    #Receive SNAC 1707, Signon reply
    r = flap()
    get(stream, r)

    if password == None:
        password = hashlib.md5(getpass.getpass("Enter Password:\n")).digest()
    
    #Create and send SNAC 1702, Logon
    key = unhexlify(r.SNAC.data[4:len(r.SNAC.data)])
    f = flap()
    f.SNAC.write1702(sn, password, key)
    send(stream,f)

    #Recieve SNAC 1703, Authentication Cookie or Error
    r = flap()
    get(stream, r)
    error = BOS = cookie = email = passchange = None
    for ii in range(0,len(r.SNAC.tlvs)):
        if(r.SNAC.tlvs[ii][0] in vars.errors):
            error = "Error: "+vars.errorMessages[vars.errorCodes.index(r.SNAC.tlvs[ii][2])] 
            return error, BOS, cookie, email, passchange
        if(r.SNAC.tlvs[ii][0] == "0005"):
            BOS = unhexlify(r.SNAC.tlvs[ii][2])
        if(r.SNAC.tlvs[ii][0] == "0006"):
            cookie = unhexlify(r.SNAC.tlvs[ii][2])
        if(r.SNAC.tlvs[ii][0] == "0011"):
            email = unhexlify(r.SNAC.tlvs[ii][2])
        if(r.SNAC.tlvs[ii][0] == "0054"):
            passchange = unhexlify(r.SNAC.tlvs[ii][2])
                
    return error, BOS, cookie, email, passchange
    stream.close()


def negotiate(BOS, cookie, email, passchange):
    vars.seq =1
    vars.flapseq = 1
    buf = 1024
    
    addr = BOS.split(':')
    addr[1] = int(addr[1])
    addr = tuple(addr)

#    print addr
    stream = socket(AF_INET, SOCK_STREAM)

    if (not stream.connect_ex(addr)):
        print "Chat Socket Connected"
    else:
        print "Connection could not be opened with BOS server"
        return
    
    #Create and send the authorization Cookie
    f = flap()
    f.writeFlap("01")
    f.SNAC.writeCookie(cookie)
    send(stream, f)

    stream.setblocking(0)



    while not (vars.capACK and vars.rateACK):
        try:
            r = flap()
            get(stream,r)
#            print vars.firstFam, vars.firstType
            if vars.firstFam == 1 and vars.firstType == 3:
                f = flap()
                f.SNAC.write117()
                send(stream, f)
            elif vars.firstFam == 1 and vars.firstType == 24:
                f = flap()
                f.SNAC.write("0001", "0006", "0000", "")
                send(stream,f)
                vars.capACK = True
            elif vars.firstFam == 1 and vars.firstType == 7:
                f = flap()
                data = ""
                for ii in vars.rates:
                    data+= str(ii.id).zfill(4)
#                print data
                f.SNAC.write("0001", "0008", "0000", data)

                send(stream,f)
                vars.rateACK = True
        except: 
            pass

    flapList = ""
    
    f = flap()
    f.SNAC.write("1", "e", "0000", "")
    flapList = addToMulti(flapList, f)
    
    f = flap()
    f.SNAC.write("13", "2", "0000", "")
    flapList = addToMulti(flapList, f)

    f = flap()
    f.SNAC.write("13", "4", "0000", "")
    flapList = addToMulti(flapList, f)

    f = flap()
    f.SNAC.write("02", "02", "0000", "")
    flapList = addToMulti(flapList, f)

    f = flap()
    f.SNAC.write("03", "02", "0000", "")
    flapList = addToMulti(flapList, f)

    f = flap()
    f.SNAC.write("04", "04", "0000", "")
    flapList = addToMulti(flapList, f)

    f = flap() 
    f.SNAC.write("9", "2", "0000", "")
    flapList = addToMulti(flapList, f)

    sendMulti(stream,flapList)



    vars.smartRead = True
    while(not vars.listACK):
        try: 
            r = flap()
            get(stream, r)
            
        except:
            
            break
    vars.smartRead = False

    sleep(.5)
    return stream

def activate(stream):
    f = flap()
    f.SNAC.write("13", "7", "0000", "")
    send(stream, f)


    f=flap()
    f.SNAC.setICBM()
    send(stream,f)

    f = flap()
    f.SNAC.write102()
    send(stream,f)

    f=flap()
    f.SNAC.write("4", "10", "0", "")
    send(stream,f)
    return stream


def startChat(stream, root=None):


    stream.setblocking(0)
    f = flap()
    while(1):
        f = flap()
        """
        try:
            message = noBlockRaw("", 1)
            if not message == "":
                if message.find(':') >= 0:
                    rec, message = message.split(':',1)
                elif message.find(' ') >= 0:
                    rec, message = message.split(' ',1)
                else:
                    rec = message
                print "COMMAND: ", rec

                if(rec == "list"):
                    print "buddylist Request"
                    f.SNAC.write1304()
                    send(stream,f)
                elif(rec == "bl"):
                    for i in vars.buddyList:
                        print i
                    for j in vars.groupList:
                        print j
               
                elif rec == "away":
                    print "Set Away"
                    f.SNAC.setAwayInfo(message)
                    send(stream, f)
                    f = flap()
                    f.SNAC.setAway()
                    send(stream, f)
                elif rec == "back":
                    print "Back from Away"
                    f.SNAC.setAwayInfo("")
                    send(stream,f)
                    f = flap()
                    f.SNAC.setBack()
                    send(stream, f)
                elif rec == "status":
                    print "Change Status"
                    f.SNAC.setStatus(message)
                    send(stream,f)
                elif rec == "exit":
                    stream.close()
                    return 
                elif rec == "add":
                    print "Add Buddy ", message
               
                    f.SNAC.addBuddy(message)
                    send(stream,f)
               
                elif rec =="rm":
                    print "Remove Buddy: ", message
                    f.SNAC.removeBuddy(message)
                    send(stream,f)

                elif rec =="off":
                    f = flap()
                    f.SNAC.getOfflineMessages()
                    send(stream,f)
                else:
                    f.SNAC.sendMessage(rec, message)
                    send(stream, f)

        except AlarmException: 
            pass
            """   
        r = flap()

        try:
            get(stream, r)
        except:
            pass





def main():

    BOS, cookie, email, passchange = authorize("login.oscar.aol.com", 5190)
    if(BOS == None):
        print "Service Could not be established"
        return
    else:
        print "Authorized User"
        
    stream = negotiate(BOS, cookie, email, passchange)

    startChat(stream, root)
    

def send(sock, data):
    sock.send(unhexlify(data.pack()))
    vars.seq = vars.seq + 1
    vars.flapseq = vars.flapseq + 1

def get(sock, flap):
    if vars.smartRead == True:
#        print "Smart read"
        packet = hexlify(sock.recv(6))
        length = int(packet[8:12], 16)
#        print packet, length
        packet = hexlify(sock.recv(length))
#        print packet
    else:
        packet = hexlify(sock.recv(1024*16))

    flap.readFlap(packet)

def addToMulti(data, flap):
    flap =  flap.pack()
    vars.flapseq = vars.flapseq + 1
    vars.seq = vars.seq + 1
    return data + flap

def sendMulti(sock, data):
    sock.send(unhexlify(data))






if "__main__" == __name__:
    main()
